﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_UTIL_FUNCTIONS_H
#define _UXS_UTIL_FUNCTIONS_H

#pragma once

#include "../CompileTime/TTypeInfo.h"

namespace UX_STL
{
namespace UXTypes
{

/*
=================================================
	возвращает номер последнего не нулевого бита
=================================================
*/
	template <typename T>
	inline uint GetMaxBitNumber(T value)
	{
		TypeDescriptor::MustBeInteger<T>();

		uint	counter	= 0;

		while ( value > 1 )
		{
			++counter;
			value >>= 1;
		}

		return counter;
	}

/*
=================================================
	возвращает номер первого не нулевого бита
=================================================
*/
	template <typename T>
	inline uint GetMinBitNumber(T value)
	{
		TypeDescriptor::MustBeInteger<T>();

		uint	counter	= 0;

		while ( (value & 1) != 1 )
		{
			++counter;
			value >>= 1;
		}

		return counter;
	}
	
/*
=================================================
	возвращает количество битов
=================================================
*/
	template <typename T>
	inline uint GetNumberOfBits(T value)
	{
		TypeDescriptor::MustBeInteger<T>();

		uint	counter = 0;

		for (uint i = 0; i < (sizeof(T) << 3); ++i)
		{
			counter += value & 1;
			value >>= 1;
		}

		return counter;
	}
	
/*
=================================================
	получить аддрес переменной
	(перегрузка операции взятия адресса не вызывается)
=================================================
*/
	template <typename T>
	inline T * AddressOf(T &tValue)
	{
		return ( (T*) &reinterpret_cast<uint8 &>( tValue ) );
	}

	template <typename T>
	inline const T * const AddressOf(const T &tValue)
	{
		return ( (const T * const) &reinterpret_cast<const uint8 &>( tValue ) ); 
	}
	
/*
=================================================
	возвращает количество элементов в статичном массиве
=================================================
*/
	template <typename T, usize I>
	inline usize CountOf(const T (&)[I])
	{
		return I;
	}

/*
=================================================
	сравнение пречисляемых типов
=================================================
*/
	template <typename T1, typename T2>
	inline bool EnumNoCmp(const T1& flags, const T2& flag)
	{
		typedef typename NearInt::MainUnsignedType<T1,T2>::type	T;

		return not ( T(flags) & T(flag) );
	}

	template <typename T1, typename T2>
	inline bool EnumCmp(const T1& flags, const T2& flag)
	{
		return not EnumNoCmp( flags, flag );
	}
	
	template <typename T1, typename T2, typename T3>
	inline bool EnumCmp(const T1& flags, const T2& mask, const T3& flag)
	{
		typedef typename NearInt::MainUnsignedType3<T1,T2,T3>::type	T;

		return ( T(flags) & T(mask) ) == T(flag);
	}
	
	template <typename T1, typename T2>
	inline bool EnumCmpE(const T1& flags, const T2& flag)
	{
		return EnumCmp( flags, flag, flag );
	}
	
	template <typename T1, typename T2, typename T3>
	inline bool EnumCmpX(const T1& flags1, const T2& flags2, const T3& mask)
	{
		typedef typename NearInt::MainUnsignedType3<T1,T2,T3>::type	T;

		return ( T(flags1) & T(mask) ) == ( T(flags2) & T(mask) );
	}
	
	template <typename T1, typename T2>
	inline bool EnumNoCmpE(const T1& flags, const T2& flag)
	{
		return not EnumCmpE( flags, flag );
	}

	
/*
=================================================
	unroll loop
=================================================
*/
	template <usize Size>
	struct UnrollLoop
	{
		template <typename T>
		inline static
		void _Iterate (T &iter)
		{
			UnrollLoop< Size-1 >::_Iterate( iter );
			iter( Size );
		}

		template <typename T>
		inline static
		void Run (T &iter)
		{
			UnrollLoop< Size-1 >::_Iterate( iter );
		}
	};


	template <>
	struct UnrollLoop <0>
	{
		template <typename T>
		inline static
		void _Iterate (T &iter)
		{
			iter( 0 );
		}
	};


//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_UTIL_FUNCTIONS_H